package dsx.dsxFrame;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import dsx.biz._BizLib;
import dsx.inf.IBizServer;
import dsx.inf.IConverter;
import dsx.inf.IDataTransfer;
import dsx.inf.INetServer;
import dsx.inf.ISlicer;
import dsx.system.DsxClassLoader;
import dsx.system.ThreadEx;

public class RPCServer implements IDataTransfer {
	IBizServer bizServer = null;
	IConverter converter = null;
	INetServer netServer = null;
	ISlicer slicer = null;
	_RPCServer config = null;

	public int getStatus() {
		synchronized (this) {
			if (this.bizServer != null)
				return this.bizServer.getStatus();
			else
				return 0;
		}
	}

	public _RPCServer getConfig() {
		synchronized (this) {
			if (config == null)
				return null;
			if (this.netServer != null)
				this.config.netServerConfig = this.netServer.getConfig();
			if (this.bizServer != null)
				this.config.status = bizServer.getStatus();
			return this.config;
		}
	}

	public ArrayList<_BizLib> getBizLibList() {
		synchronized (this) {
			if (bizServer != null)
				return bizServer.getBizList();
			else
				return null;
		}
	}

	public void reloadBizLib() {
		if (bizServer != null)
			bizServer.reloadBizMap();
	}

	public void reloadBizLib(String libName) {
		if (bizServer != null)
			bizServer.reloadBiz(libName);
	}

	public void init(_RPCServer config) {
		synchronized (this) {
			if (this.config != null && this.config.equals(config))
				return;
			boolean started = false;
			if (bizServer != null) {
				if (bizServer.getStatus() == 1) {
					stopNoSync();
					started = true;
				}
			}
			this.config = config;
			createSlicer();
			createConverter();
			createNetServer();
			createBizServer();
			this.netServer.init(config.netServerName, this, this.slicer);
			this.bizServer.init(config.bizServerName, config.path, this, this.converter,
					config.bizDebugEnabled);
			if (config.autoStart == 1 || started)
				startNoSync();
		}
	}

	public boolean start() {
		synchronized (this) {
			return startNoSync();
		}
	}

	public void stop() {
		synchronized (this) {
			stopNoSync();
		}
	}

	public boolean restart() {
		synchronized (this) {
			stopNoSync();
			return startNoSync();
		}
	}

	private boolean startNoSync() {
		if (bizServer == null || netServer == null || converter == null)
			return false;
		if (!netServer.start()) {
			return false;
		}
		if (!bizServer.start()) {
			netServer.stop();
			return false;
		} else {
			return true;
		}
	}

	private void stopNoSync() {
		if (bizServer != null) {
			bizServer.stop();
			while (bizServer.getStatus() != 0) {
				ThreadEx.sleepEx(20);
			}
		}
		if (netServer != null)
			netServer.stop();
		synchronized (workers) {
			workers.notifyAll();
		}
		for (WorkerThread worker : workers)
			worker.stopEx();
		workers.clear();
		dataQueue.clear();
	}

	private void createSlicer() {
		try {
			if (config.slicerClass.equals("")) {
				slicer = null;
			} else {
				ClassLoader classLoader = DsxClassLoader.frameClassLoader();
				slicer = (ISlicer) classLoader.loadClass(config.slicerClass)
						.newInstance();
			}
		} catch (Exception ex) {
			slicer = null;
		}
	}

	private void createNetServer() {
		try {
			ClassLoader classLoader = DsxClassLoader.frameClassLoader();
			netServer = (INetServer) classLoader.loadClass(
					config.netServerClass).newInstance();
		} catch (Exception ex) {
			netServer = null;
		}
	}

	private void createConverter() {
		try {
			ClassLoader classLoader = DsxClassLoader.frameClassLoader();
			converter = (IConverter) classLoader.loadClass(
					config.converterClass).newInstance();
		} catch (Exception ex) {
			converter = null;
		}
	}

	private void createBizServer() {
		try {
			ClassLoader classLoader = DsxClassLoader.frameClassLoader();
			bizServer = (IBizServer) classLoader.loadClass(
					config.bizServerClass).newInstance();
		} catch (Exception ex) {
			bizServer = null;
		}
	}

	@Override
	public boolean recv(Object pipe, byte[] data) {
		try {
			synchronized (dataQueue) {
				DsxData dsxData = new DsxData();
				dsxData.pipe = pipe;
				dsxData.data = data;
				dataQueue.add(dsxData);
			}
			awakeWorker();
			return true;
		} catch (Exception ex) {
			return false;
		}
	}

	@Override
	public boolean send(Object pipe, byte[] data) {
		try {
			if (netServer != null) {
				netServer.send(pipe, data);
				return true;
			}
		} catch (Exception ex) {
		}
		return false;
	}

	Queue<DsxData> dataQueue = new LinkedList<DsxData>();

	List<WorkerThread> workers = new ArrayList<WorkerThread>();

	private void awakeWorker() {
		synchronized (workers) {
			if (workers.size() == 0
					|| (workers.size() < config.maxWorkerNum && dataQueue
							.size() > 3)) {
				WorkerThread worker = new WorkerThread();
				worker.rpcServer = this;
				workers.add(worker);
				worker.start();
			} else {
				workers.notify();
			}
		}
	}

	private class DsxData {
		Object pipe;
		byte[] data;
	}

	private class WorkerThread extends ThreadEx {

		RPCServer rpcServer = null;

		@Override
		protected void doInLoop() {
			try {
				if (rpcServer != null && rpcServer.bizServer != null
						&& rpcServer.bizServer.getStatus() == 1) {
					while (true) {
						DsxData dsxData = null;
						synchronized (rpcServer.dataQueue) {
							dsxData = rpcServer.dataQueue.poll();
						}
						if (dsxData == null)
							break;
						rpcServer.bizServer.handle(dsxData.pipe, dsxData.data);
					}
				}
				synchronized (rpcServer.workers) {
					rpcServer.workers.wait();
				}
			} catch (Exception ex) {

			}
		}
	}

}
